package com.quan.pm.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.quan.commons.core.MyBaseServiceImpl;
import com.quan.commons.interceptor.LoginUserInterceptor;
import com.quan.commons.utils.DateUtils;
import com.quan.commons.utils.PageUtils;
import com.quan.hr.entity.HrDept;
import com.quan.hr.service.HrCalendarService;
import com.quan.hr.service.HrDeptService;
import com.quan.hr.service.HrEmployeeService;
import com.quan.pm.commons.vo.PmProjectCenterVo;
import com.quan.pm.commons.vo.PmProjectDevEmpVo;
import com.quan.pm.entity.PmProjectCenter;
import com.quan.pm.entity.PmProjectDevEmp;
import com.quan.pm.mapper.PmProjectCenterMapper;
import com.quan.pm.service.PmProjectCenterService;
import com.quan.pm.service.PmProjectDevEmpService;
import com.quan.system.commons.vo.SysSchedulerVo;
import com.quan.system.commons.vo.SysUserVo;
import com.quan.system.service.SysSchedulerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
@DS("master")
public class PmProjectCenterServiceImpl extends MyBaseServiceImpl<PmProjectCenterMapper, PmProjectCenter> implements PmProjectCenterService {

    @Autowired
    private PmProjectCenterMapper mapper;

    @Autowired
    private HrDeptService departService;

    @Autowired
    private HrEmployeeService employeeService;

    @Autowired
    private SysSchedulerService jobService;

    @Autowired
    private PmProjectDevEmpService projectDevEmpService;

    @Autowired
    private HrCalendarService calendarService;

    @Transactional
    @Override
    public boolean save(PmProjectCenterVo vo) {

        // 保存开发人员信息
        if(null != vo.getDevs() && !vo.getDevs().isEmpty()) {
            List<PmProjectDevEmp> collect = vo.getDevs().stream().map(item -> {
                PmProjectDevEmp dev = new PmProjectDevEmp();
                BeanUtils.copyProperties(item, dev);
                return dev;
            }).collect(Collectors.toList());
            this.projectDevEmpService.saveBatch(collect);
        }


        // 操作人
        final SysUserVo user = LoginUserInterceptor.loginUser.get();
        vo.setCname(null != user.getEmpName() ? user.getEmpName() : user.getUsername());

        return super.save(vo);
    }

    @Override
    public boolean updateById(PmProjectCenterVo vo) {

        // 设置部门名称
        if(null != vo.getDeptId()) {
            final HrDept dept = this.departService.getById(vo.getDeptId());
            if(null != dept) {
                vo.setDeptName(dept.getName());
            }
        }

        // 保存开发人员信息
        if(null != vo.getDevs() && !vo.getDevs().isEmpty()) {
            // 删除原有开发人员信息
            this.projectDevEmpService.remove(new QueryWrapper<PmProjectDevEmp>().lambda().eq(PmProjectDevEmp::getProjectId, vo.getId()));

            List<PmProjectDevEmp> collect = vo.getDevs().stream().map(item -> {
                PmProjectDevEmp dev = new PmProjectDevEmp();
                item.setId(null);
                BeanUtils.copyProperties(item, dev);
                return dev;
            }).collect(Collectors.toList());
            this.projectDevEmpService.saveBatch(collect);
        }

        final SysUserVo user = LoginUserInterceptor.loginUser.get();
        vo.setUname(null != user.getEmpName() ? user.getEmpName() : user.getUsername());

        final boolean flag = super.updateById(vo);


        // 定时作业：项目信息邮件提醒
        this.settingProjectInfoScheduler(vo);

        // TODO 定时作业：项目开发人员邮件提醒

        return flag;
    }

    /**
     * 项目结束提醒邮件，定时器设置
     * 两个定时器【1：项目结束前3天邮件提醒，2：项目结束邮件提醒】
     * @param vo
     */
    @Async
    private void settingProjectInfoScheduler(PmProjectCenterVo vo) {
        try {
            // 项目结束前3天作为定时
            LocalDate d1 = vo.getEndDate().minusDays(3);
            // 项目结束时间作为定时
            LocalDate d2 = vo.getEndDate();

            // 项目结束前3天触发（30秒 30分 23时 日 月 [周] 年）
            String cron1 = "30 30 23 " + d1.getDayOfMonth() + " " + d1.getMonthValue() + " ? " + d1.getYear();
            // 项目结束日期触发（30秒 30分 23时 日 月 [周] 年）
            String cron2 = "30 30 23 " + d2.getDayOfMonth() + " " + d2.getMonthValue() + " ? " + d2.getYear();


            // ==============================提前3天邮件提醒=========================== //
            SysSchedulerVo job = new SysSchedulerVo();
            job.setJobCron(cron1);
            job.setJobClassPath("com.quan.pm.scheduler.ProjectInfoEarlierMailNotifyJob");

            job.setJobName("项目结束邮件提醒（前3天）["+vo.getCode()+"]");
            job.setJobDesc("项目名称【"+vo.getName()+"】项目结束日期【"+vo.getEndDate()+"】");

            // 定时参数
            Map<String, Object> jobDataMap = new HashMap<String, Object>();
            jobDataMap.put("projectId", vo.getId());
            job.setJobDataMap(jobDataMap);
            job.setJobParams(JSON.toJSONString(jobDataMap));

            this.jobService.startJob(job);

            // ==============================项目结束日期邮件提醒=========================== //
            SysSchedulerVo job2 = new SysSchedulerVo();
            job2.setJobCron(cron2);
            job2.setJobClassPath("com.quan.pm.scheduler.ProjectInfoFinishMailNotifyJob");

            job2.setJobName("项目结束邮件提醒["+vo.getCode()+"]");
            job2.setJobDesc("项目名称【"+vo.getName()+"】项目结束日期【"+vo.getEndDate()+"】");

            // 定时参数
            Map<String, Object> jobDataMap2 = new HashMap<String, Object>();
            jobDataMap2.put("projectId", vo.getId());
            job2.setJobDataMap(jobDataMap2);
            job2.setJobParams(JSON.toJSONString(jobDataMap2));

            this.jobService.startJob(job2);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public PmProjectCenterVo getInfo(Long id) {
        final PmProjectCenter projectCenter = super.getById(id);

        PmProjectCenterVo bean = new PmProjectCenterVo();
        BeanUtils.copyProperties(projectCenter, bean);

        if(null != bean.getDeptId()) {
            // 部门反推获取节点的父路径
            bean.setCascaderDeptPathVals(this.departService.findPath(bean.getDeptId()));
        }

        // 获取开发人员信息
        final LambdaQueryWrapper<PmProjectDevEmp> lambdaDev = new QueryWrapper<PmProjectDevEmp>().lambda();
        lambdaDev.eq(PmProjectDevEmp::getProjectId, id);
        lambdaDev.orderByAsc(PmProjectDevEmp::getStatus);

        List<PmProjectDevEmp> devList = this.projectDevEmpService.list(lambdaDev);
        List<PmProjectDevEmpVo> collect = devList.stream().map(item -> {
            PmProjectDevEmpVo devVo = new PmProjectDevEmpVo();
            BeanUtils.copyProperties(item, devVo);
            return devVo;
        }).collect(Collectors.toList());
        bean.setDevs(collect);

        return bean;
    }

    @Override
    public List<PmProjectCenterVo> queryList(PageUtils pageUtils, PmProjectCenterVo vo) {
        QueryWrapper<PmProjectCenter> queryWrapper = new QueryWrapper<PmProjectCenter>(vo);

        List<PmProjectCenter> list = super.list(pageUtils, queryWrapper);
        List<PmProjectCenterVo> collect = list.stream().map(item -> {
            PmProjectCenterVo bean = new PmProjectCenterVo();
            BeanUtils.copyProperties(item, bean);
            return bean;
        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public PageUtils queryPage(PageUtils pageUtils, PmProjectCenterVo vo) {
        QueryWrapper<PmProjectCenter> queryWrapper = new QueryWrapper<PmProjectCenter>(vo);

        if (StringUtils.isNotBlank(vo.getKeyword())) {
            queryWrapper.and(w -> {
                w.like("name", vo.getKeyword()).or().like("code", vo.getKeyword());
            });
        }

        // 项目开始日期范围
        if (StringUtils.isNotEmpty(vo.getStartDateRange())) {
            final String[] split = vo.getStartDateRange().split(",");
            String startDate = split[0];
            String endDate = split[1];
            queryWrapper.apply("date_format(start_date, '%Y-%m-%d') >= {0} and date_format(start_date, '%Y-%m-%d') <= {1}", startDate, endDate);
        }

        // 项目结束日期范围
        if (StringUtils.isNotEmpty(vo.getEndDateRange())) {
            final String[] split = vo.getEndDateRange().split(",");
            String startDate = split[0];
            String endDate = split[1];
            queryWrapper.apply("date_format(end_date, '%Y-%m-%d') >= {0} and date_format(end_date, '%Y-%m-%d') <= {1}", startDate, endDate);
        }

        super.handleSort(queryWrapper, pageUtils);
        final IPage<PmProjectCenter> page = super.selectPage(pageUtils, queryWrapper);

        PageUtils ps = new PageUtils(page);

        final List<PmProjectCenter> records = page.getRecords();

        final List<PmProjectCenter> collect = records.stream().map((item) -> {
            PmProjectCenterVo bean = new PmProjectCenterVo();
            BeanUtils.copyProperties(item, bean);

            // 项目天数
            bean.setAllDays(DateUtils.betweenDays(bean.getStartDate(), bean.getEndDate()));
            // 项目实际工作天数，不计算周末和节假日
            bean.setWorkingDays(this.calendarService.getBetweenCalendarWorkingCount(bean.getStartDate(), bean.getEndDate()));

            return bean;
        }).collect(Collectors.toList());

        ps.setRecords(collect);
        return ps;
    }
}